package aqs;

import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Lock;

public class ReentrantLock {
    private final Sync sync;
    // 默认构造器：非公平锁
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    abstract static class Sync extends AbstractQueuedSynchronizer {
        // 用于实现非公平锁的获取锁方法
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            //  如果此时有线程正好释放了锁，直接抢锁。
            //和公平锁唯一不同的地方在于：这里不看队列有没有线程排队，直接CAS抢锁。
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");//超过最大锁计数
                setState(nextc);
                return true;
            }
            return false; // 抢锁失败，告知AQS，将线程 排队 并阻塞。
        }
    }
    // 非公平锁获取锁的流程
    static final class NonfairSync extends Sync {
        final void lock() {
            if (compareAndSetState(0, 1)) // 直接抢锁。上来先抢锁
                setExclusiveOwnerThread(Thread.currentThread()); // 抢成功了之后呢？标识当前属于我了
            else
                acquire(1); // 否则进入AQS的acquire模板方法。否则进入常规操作
        }

        // AQS的模板方法回调此方法，来判断子类是否获取锁成功。
        // AQS的acquire方法，回调，用于判定是否获取锁成功。
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
    // 公平锁获取锁的流程
    static final class FairSync extends Sync {
        final void lock() {
            acquire(1); // 直接进入常规操作，不直接抢锁
        }

        /* Fair version of tryAcquire.  Don't grant access unless recursive call or no waiters or is first.
           公平锁版本的tryAcquire实现。    不保证访问（不保证能够获得到锁），除非递归调用  或者没有等待的线程 或者是第一个。
         */
        // AQS的acquire方法，回调，用于判定是否获取锁成功
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            // 拿到锁变量
            int c = getState();
            // c=0：没有线程获取锁
            if (c == 0) { //如果没有线程获取锁
                /*  hasQueuedPredecessors：队列里面有没有别的线程正在等待，
                  !（取反），&&（与）：就是 如果没有那么。
                  如果没有那么抢锁 compareAndSetState(0, acquires)。
                */
                if (!hasQueuedPredecessors() &&
                        compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current); // 抢锁成功，设置标记：锁归我了
                    return true; // 返回AQS true，告诉AQS：我拿到锁了，别给我走 排队->阻塞
                }
            }
            // 当前线程就是获取锁的那个线程，所以直接 state + acquires 即可。
            // 重入锁，多次lock。
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false; //如果 c != 0，说明锁被占用。则不去抢锁，直接 return false。
        }
    }
}
